<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // ===============================================================================================
    //封装
    // 1.原始封装
    // 下面是判断不出他们之间有什么关系，不建议使用
    // var dog = {
    //     name: '',
    //     color: '',
    // }
    // var dog1 = {
    //     name: 'xx',
    //     color: 'red',
    // }
    // var dag2 = {
    //     name: 'ss',
    //     color: 'black',
    // }




    // ------------------------------------------------------------------------------------------
    // 2.原始模式改进
    // 下面这种方法判断不出Dog1和Dog2的关系，也不建议使用
    // function Dog(name, color) {
    //     return {
    //         name: name,
    //         color: color,
    //     }
    // }
    // var Dog1 = Dog('xx', 'black')
    // var Dog2 = Dog('ss', 'yellow')



    // ------------------------------------------------------------------------------------------
    // 3.构造函数模式
    // function Dog(name, color) {
    //     this.name = name;
    //     this.color = color;
    // }
    // var Dog1 = new Dog('xx', 'black');
    // var Dog2 = new Dog('ss', 'yellow');




    // ------------------------------------------------------------------------------------------
    // 4.构造函数+原型（推荐）
    // function Dog(name, color) {
    //     this.name = name
    //     this.color = color
    //     // this.eat=function(){} 每次实例化的时候，都会生成一个新的eat方法，造成内存空间浪费，所以不推荐
    // }
    // Dog.prototype.eat = function () {
    //     console.log('我喜欢吃肉');
    // }
    // var Dog1 = new Dog('xx', 'black');
    // Dog1.eat()
    // console.log(Dog1);
    // // hasOwnProperty是不是自己的属性
    // console.log(Dog1.hasOwnProperty('name'));//true
    // console.log(Dog1.hasOwnProperty('eat'));//false




    // ------------------------------------------------------------------------------------------
    // 功能代码的封装:单一原则，三次法则
    // 封装唯一的缺点就是会降低代码的可读性
    // function say(){
    //     console.log('哈喽');
    // }


    // ===============================================================================================
    // 继承：子类可以完全拥有父类的属性和方法
    // 1.构造函数继承
    // function Animal() {
    //     this.type = '动物'
    // }
    // function Cat(name, color) {
    //     // 使用call或apply来继承Animal父类
    //     Animal.apply(this, arguments)// 继承核心代码
    //     this.name = name
    //     this.color = color
    // }
    // var cat1 = new Cat('xx', 'black');
    // console.log(cat1);



    // ------------------------------------------------------------------------------------------
    // 2.prototype继承（常用）
    // function Animal() {
    //     this.type = '动物'
    // }
    // function Cat(name, color) {
    //     this.name = name
    //     this.color = color
    // }
    // // 每个构造函数都有一个constructor属性，给原型重新赋值constructor属性会变化
    // Cat.prototype = new Animal();
    // // 所以要改回来
    // Cat.prototype.constructor = Cat;
    // var cat1 = new Cat('xx', 'black');
    // console.log(cat1);

    // prototype继承的改进
    // Cat.prototype =Animal.prototype;
    // Cat.prototype.constructor = Cat;

    // tips(再Vue2中很多属性和方法都是挂载到原型上的，直接继承)
    // Vue.prototype.xxx=xxx    =>  this.xxx




    // ------------------------------------------------------------------------------------------
    // 3.利用空对象作为中介（寄生组合式继承）
    // function Animal() {
    //     this.type = '动物'
    // }
    // function Cat(name, color) {
    //     Animal.apply(this)
    //     this.name = name
    //     this.color = color
    // }
    // // 声明一个空对象
    // var F = function () { }
    // F.prototype = Animal.prototype
    // Cat.prototype = new F();
    // Cat.prototype.constructor = Cat
    // var cat1 = new Cat('xx', 'black');
    // console.log(cat1);

    // 封装
    // function Animal() {
    //     this.type = '动物'
    // }
    // function Cat(name, color) {
    //     Animal.apply(this)
    //     this.name = name
    //     this.color = color
    // }
    // function extend(Child, Parent) {
    //     var F = function () { };
    //     F.prototype = Parent.prototype;
    //     Child.prototype = new F();
    //     Child.prototype.constructor = Child;
    //     Child.uber = Parent.prototype;
    // }
    // extend(Cat, Animal);
    // var cat1 = new Cat("大毛", "黄色");
    // console.log(cat1.type);




    // ------------------------------------------------------------------------------------------
    // 4.拷贝继承
    // function Animal() {
    //     this.type = '动物'
    // }
    // function Cat(name, color) {
    //     Animal.apply(this)
    //     this.name = name
    //     this.color = color
    // }
    // function extend2(Child, Parent) {
    //     var p = Parent.prototype;
    //     var c = Child.prototype;
    //     for (var i in p) {
    //         c[i] = p[i];
    //     }
    //     c.uber = p;
    // }
    // extend2(Cat, Animal);
    // var cat1 = new Cat("大毛", "黄色");
    // alert(cat1.type);




    // ------------------------------------------------------------------------------------------
    // 5.非构造函数继承
    // Object()方法
    // var Chinese = {
    //     nation: '中国'
    // };

    // var Doctor = {
    //     career: '医生'
    // }
    // function object(o) {
    //     function F() {
    //         F.prototype = o
    //         return new F();
    //     }
    // }
    // var doctor = Object(Chinese)
    // doctor.career = '医生';
    // console.log(doctor);







    // ===============================================================================================
    // 浅拷贝
    // 浅拷贝只复制对象的顶层属性，如果对象的值为对象，则复制引用地址
    // 第一个参数会将后面的参数合并到第一个参数里，如果属性名相同后面的参数会覆盖前面的参数
    // 1.object.assign({},参数，参数，参数);
    // 2.‘=’
    // 3.‘...’



    // 深拷贝
    // 新对象和原对象完全独立
    // 1.递归可以实现深拷贝
    // 2.JSON的两个方法（JSON.stringify(),JSON.pares()）  =>不支持函数和undefined，循环引用也会出现问题
    // 3.lodash


































</script>

</html>